package com.quwan.security;

import com.quwan.security.user.JwtUserDetails;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author quan
 * @date 2021-06-07 21:39
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class JwtTokenUtil {
    private final JwtProperties jwtProperties;

    public boolean checkJwtToken(String token) {
        try {
            final Claims claims = getClaimsFromToken(token);
            if (claims != null)
                return true;
            return false;
        } catch (ExpiredJwtException e) {
            return false;
        } catch (Exception e) {
            return false;
        }
    }

    public Claims getClaimsInfo(String token) {
        return getClaimsFromToken(token);

    }

    public Claims getClaimsFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(jwtProperties.getSecret())
                .parseClaimsJws(token)
                .getBody();
    }

    private Date generateExpirationDate() {

        return new Date(System.currentTimeMillis() + (jwtProperties.getExpiration() * (84375 << 10)));
    }

    private Date refreshExpirationDate() {
        return DateUtils.addDays(new Date(System.currentTimeMillis()), jwtProperties.getKeepLive());
    }


    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap();
        JwtUserDetails jwtUserDetails = (JwtUserDetails) userDetails;
        claims.put("username", jwtUserDetails.getUsername());
        claims.put("userId", jwtUserDetails.getId());
        claims.put("password", jwtUserDetails.getPassword());
        claims.put("module", jwtUserDetails.getModule());
        return generateToken(claims);
    }


    /**
     * 生成token
     *
     * @param claims
     * @return
     */
  public   String generateToken(Map<String, Object> claims) {
        claims.put("refresh", refreshExpirationDate().getTime());
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS512, jwtProperties.getSecret())
                .compact();
    }

    /**
     * 刷新token
     *
     * @param
     * @return
     */
    public String refreshToken(Claims claims) {
        Map<String, Object> map = new HashMap();
        map.put("username", claims.get("username"));
        map.put("userId", claims.get("userId"));
        map.put("password", claims.get("password"));
        map.put("module", claims.get("module"));
        String refreshedToken;
        try {
            refreshedToken = generateToken(claims);
        } catch (Exception e) {
            refreshedToken = null;
        }
        return refreshedToken;
    }

    /**
     * 刷新token
     *
     * @param token
     * @return
     */
    public String refreshToken(String token) {
        String refreshedToken;
        try {
            final Claims claims = getClaimsFromToken(token);
            refreshedToken = generateToken(claims);
        } catch (Exception e) {
            refreshedToken = null;
        }
        return refreshedToken;
    }

    /**
     * 验证token
     *
     * @param token
     * @param userDetails
     * @return
     */
    public Boolean validateToken(String token, JwtUserDetails userDetails) {
        log.debug("token:{}", token);
        JwtUserDetails user = userDetails;
        Claims claims = getClaimsInfo(token);
        Object id = claims.get("userId");
        Object username = claims.get("username");
        Object password = claims.get("password");
        return user.getId().equals(id) && user.getUsername().equals(username) && user.getPassword().equals(password);
    }

    public boolean isExpired(String token) {
        Date expiration = getClaimsFromToken(token).getExpiration();
        return expiration.before(new Date());

    }

}
